<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>贪吃蛇</title>
    <style>
      /* canvas{
            border: 1px solid black;
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
            margin: auto;
            transform: scale(4);
            color: #55695e;
        } */
      html {
        height: 100%;
        width: 100%;
      }
      body {
        margin: 0;
        padding: 0;
        background-color: #7193a7;
        position: relative;
        height: 100%;
        width: 100%;
      }
      canvas {
        border: 1px solid #c28c6f;
        position: absolute;
        border-radius: 2px;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        margin: 5% auto;
        width: 80%;
        aspect-ratio: 1;
        max-height: 80vh;
        background-color: #e8d2c1;
        image-rendering: pixelated;
      }
      .scores {
        color: #e8d2c1;
        text-align: center;
        height: 45px;
        font-size: 24px;
        padding: 10px;
      }
      .mask {
        /* display: none; */
        opacity: 0;
        transition: all 0.5s;
        background-color: rgb(0, 0, 0, 0.8);
        height: 100%;
        width: 100%;
        position: absolute;
        top: 0px;
      }
      span {
        display: block;
        margin-top: 200px;
        width: 100%;
        text-align: center;
        font-size: 46px;
        font-family: "Times New Roman", Times, serif;
        color: orangered;
      }
      button {
        background-color: orange;
        color: red;
        font-size: 26px;
        height: 70px;
        width: 200px;
        position: absolute;
        border-radius: 10px;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        margin: auto;
      }
    </style>
  </head>
  <body>
    <div class="scores">得分: 0</div>
    <canvas></canvas>
    <div class="mask">
      <span>Game Over</span>
      <button>Try again!</button>
    </div>
    <script>
      function createSnake() {
        let snake = {
          body: [
            { x: 50, y: 50 },
            { x: 51, y: 50 },
            { x: 52, y: 50 },
            { x: 53, y: 50 },
          ], //这样写比数组套数组好一点,x,y可以分得很清楚

          direction: "left", //给个初始方向左
          move() {
            let head = this.body[0]

            let newHead = {} //改变方向之后的新头

            switch (
              this.direction //写个this后面绑定事件的时候好用
            ) {
              case "right":
                newHead = { x: head.x + 1, y: head.y }
                break
              case "left":
                newHead = { x: head.x - 1, y: head.y }
                break
              case "up":
                newHead = { x: head.x, y: head.y - 1 }
                break
              case "down":
                newHead = { x: head.x, y: head.y + 1 }
                break
            }

            this.body.unshift(newHead) //添加一个新的坐标到前面

            this.body.pop() //删除最后一个,不删的话会无限延长

            //之前的做法是后一个继承前一个的坐标,但是不知道怎么处理最后一个
          },
          grow() {
            let tail = this.body[this.body.length - 1]
            let newTail

            switch (this.direction) {
              case "right":
                newTail = { x: tail.x - 1, y: tail.y }
                break
              case "left":
                newTail = { x: tail.x + 1, y: tail.y }
                break
              case "up":
                newTail = { x: tail.x, y: tail.y + 1 }
                break
              case "down":
                newTail = { x: tail.x, y: tail.y - 1 }
                break
            }
            this.body.push(newTail) //吃了之后添加一个新的
          },

          draw(ctx) {
            ctx.fillStyle = "#55695e"

            //写this的好处就是谁调用就指向谁

            this.body.forEach(function (segment) {
              ctx.fillRect(segment.x, segment.y, 1, 1)
            })
          },
          checkCollision() {
            let head = this.body[0]
            for (let i = 1; i < this.body.length; i++) {
              if (head.x === this.body[i].x && head.y === this.body[i].y) {
                return true
              }
            }
            if (head.x < 0 || head.x > 100 || head.y < 0 || head.y > 100) {
              return true
            }

            return false
          }, //判断模块,写在这里后面直接用返回值判断
        }
        return snake //是个对象,只是不明显
      }

      let scores = 0 //分数给个默认值

      function getRandomColor() {
        const r = Math.floor(Math.random() * 200)
        const g = Math.floor(Math.random() * 200)
        const b = Math.floor(Math.random() * 200)
        return (color = `rgb(${r},${g},${b})`)
      }

      function createFood() {
        let food = {
          x: Math.floor(Math.random() * 300),

          y: Math.floor(Math.random() * 300),

          draw(ctx) {
            ctx.fillStyle = getRandomColor()

            ctx.fillRect(this.x, this.y, 1, 1)
          },
        }

        return food
      }

      // 获取canvas
      let canvas = document.querySelector("canvas")
      let ctx = canvas.getContext("2d")

      let snake = createSnake()

      let foods = []

      //绑定按键
      window.addEventListener("keydown", function (event) {
        switch (event.key) {
          case "ArrowLeft":
            if (snake.direction !== "right") {
              snake.direction = "left"
            }
            break
          case "ArrowUp":
            if (snake.direction !== "down") {
              snake.direction = "up"
            }
            break
          case "ArrowRight":
            if (snake.direction !== "left") {
              snake.direction = "right"
            }
            break
          case "ArrowDown":
            if (snake.direction !== "up") {
              snake.direction = "down"
            }
            break
        }
      })

      // 添加20个随机位置的食物的坐标
      for (let i = 0; i < 20; i++) {
        foods.push(createFood()) //添加的是坐标的对象{x,y}
      }

      // 游戏不断刷新和判断的函数
      function gameLoop() {
        // 移动
        snake.move()

        // 检查是否吃到食物
        for (let i = 0; i < foods.length; i++) {
          if (
            snake.body[0].x === foods[i].x &&
            snake.body[0].y === foods[i].y
          ) {
            snake.grow()

            foods.splice(i, 1) //吃了就删掉

            foods.push(createFood()) //然后填一个新的

            document.querySelector(".scores").innerHTML = `得分: ${++scores}`

            break //检测到吃了就不要监测后面了
          }
        }

        // 碰撞检测模块--以函数的返回值判断(61行)

        if (snake.checkCollision()) {
          // alert('你好菜')

          document.querySelector(".mask").style.opacity = 1

          clearInterval(timer) //碰撞了就不要再继续了
        }

        // 清除画面,先清除,再画上
        ctx.clearRect(0, 0, canvas.width, canvas.height) //也可以写100和100,就是后面可能会改,然后这样写要方便一点

        //console.log(ctx)//看看ctx是什么,是画板canvas的内容对象

        snake.draw(ctx) //这样传参可以对不同的模块加不同的颜色/设置属性等

        for (let i = 0; i < foods.length; i++) {
          foods[i].draw(ctx) //循环画方块(食物)
        }
      }

      document.querySelector("button").addEventListener("click", function () {
        location.reload()
      })

      let timer = setInterval(gameLoop, 30)
    </script>
  </body>
</html>
